package server

import (
	"github.com/akirakazu/go-simplejson"
	"github.com/akirakazu/log4go"
	"os"
	"path/filepath"
	"strconv"
)

func IsIDC() bool {
	hostname, _ := os.Hostname()
	if hostname == PROXY_URI {
		return true
	} else {
		return false
	}
}

// Teleport server
type Server struct {
	logLineLength int
	binDir        string
	cert          string
	key           string
	proxy         *Proxy
	pb            *portBinder
	conns         map[string]*Conn
	caches        map[string]string
	listeners     map[string]map[string]*listener
}

// Constructor for wss server
func NewSSLServer() *Server {
	s := new(Server)
	s.initBinDir()
	s.initCert()
	s.pb = newSSLPortBinder(s)
	s.conns = map[string]*Conn{}
	s.caches = map[string]string{}
	s.listeners = map[string]map[string]*listener{}

	if !IsIDC() {
		s.proxy = newProxy(s)
	} else {
		s.proxy = nil
	}

	s.Start()
	return s
}

// Send a package to a conn by id
func (s *Server) send(id string, p *Pack) {
	s.pb.sendPack(id, p)
}

// Send a 'response' package to a conn by id
// retrive packge's id from m
func (s *Server) response(id string, m *Pack, msg *json.Json) {
	p := NewPackWithId(m.Id, "response", msg)
	s.pb.sendPack(id, p)
}

func (s *Server) iterateListeners(msg *json.Json) {
	for _, v := range s.listeners {
		for _, v1 := range v {
			if PatternMatch(v1.pattern, msg) {
				res := json.New()
				res.Set("pattern", v1.pattern)
				res.Set("event", msg)
				p := NewPackWithId(v1.id, "event", res)
				s.send(v1.connId, p)
			}
		}
	}
}

func (s *Server) closeConn(id string) {
	if _, ok := s.conns[id]; ok {
		mgrid := JSONToString(s.conns[id].identity)
		delete(s.listeners, mgrid)
		delete(s.conns, id)
	}

	// Remove caches
	for key, value := range s.caches {
		if value == id {
			delete(s.caches, key)
		}
	}
}

func (s *Server) isProxyConn(id string) bool {
	conn, ok := s.conns[id]
	if !ok {
		return false
	}
	client_type, err := conn.identity.GetString("client_type")
	if err != nil {
		return false
	}
	// "client_type" == "__proxy"
	if client_type != "__proxy" {
		return false
	}
	return true
}

func (s *Server) Start() {
	s.pb.start()
}

func (s *Server) logPack(direction string, m *Pack, addr string) {
	content := JSONToString(m.Msg)
	if s.logLineLength != 0 && len(content) > s.logLineLength {
		content = content[0:s.logLineLength] + "..."
	}

	var fromto string
	if direction == "send" {
		fromto = "to"
	} else {
		fromto = "from"
	}

	log.Println("%s %s %s %s: %s", direction, m.Cmd, fromto, addr, content)
}

func (s *Server) logBinary(direction string, p []byte, addr string) {
	var fromto string
	if direction == "send" {
		fromto = "to"
	} else {
		fromto = "from"
	}
	log.Println("%s %d bytes %s %s", direction, len(p), fromto, addr)
}
